from google.appengine.ext import webapp, db
from google.appengine.ext.webapp.util import run_wsgi_app 
from google.appengine.api import memcache, datastore_errors 
from google.appengine.runtime import DeadlineExceededError

from marketdata.models import *
from marketdata.statistic import TradeHubs

from datetime import  datetime, timedelta

import logging



class MainPage(webapp.RequestHandler): 
    def get(self): 
        self.response.headers['Content-Type'] = 'text/html' 
        try:
            inboundmailkeys = Mail.all(keys_only = True).fetch(50)
            for inboundmailkey in inboundmailkeys:
                try:
                    inboundmail = Mail.get(inboundmailkey)
                    _processed = 0
                    if inboundmail.body != None:
                        marketlist = inboundmail.body.split("\n")
                        marketlistLen = len(marketlist)
                        cachedkey = str(inboundmailkey)
                        logging.info("Work with mail ID = %s from date %s by %s with %d lines." % (cachedkey,inboundmail.date,inboundmail.sender,marketlistLen))
                        if (marketlistLen > 1) and (marketlist[0] == "price,volRemaining,typeID,range,orderID,volEntered,minVolume,bid,issued,duration,stationID,regionID,solarSystemID,jumps,source") :
                            uploaded = datetime.strptime(inboundmail.date.split(' +',1)[0],"%a, %d %b %Y %H:%M:%S")
                            marketlist.pop(0)
                            typeID = None
                            solarSystemID = None
                            cachedStartFrom = memcache.get(cachedkey)
                            marketlistStartFrom = 0
                            if cachedStartFrom is not None:
                                marketlistStartFrom = cachedStartFrom
                                logging.info("Found cached info. Starting from line %d." % (marketlistStartFrom))
                            for marketlistIndex in range (marketlistStartFrom,marketlistLen-2) :
                                try:
                                    marketstat = marketlist[marketlistIndex].split(',')
                                    if len(marketstat) == 15:
                                        # for only jita handling
                                        if long(marketstat[12]) in TradeHubs:
                                             tdate = datetime.strptime(marketstat[8].split('.',1)[0],"%Y-%m-%d %H:%M:%S")
                                             if typeID != marketstat[2] and solarSystemID != marketstat[12]:
                                                 if typeID != None :
                                                     try:
                                                         _processed += db.run_in_transaction(self.store_result,uploaded,long(typeID),long(regionID),long(solarSystemID),ordersdata,sellprices,buyprices)
                                                         if not memcache.set(cachedkey, marketlistIndex):
                                                             logging.error("Memcache set failed.")
                                                     except (DeadlineExceededError, datastore_errors.Timeout):
                                                         logging.info("Aborted at line %d. Processed %d records." % (marketlistIndex,_processed))
                                                         return
                                                 typeID = marketstat[2]
                                                 regionID = marketstat[11]
                                                 solarSystemID = marketstat[12]
                                                 sellprices = []
                                                 buyprices = []
                                                 ordersdata = [None,None,0,0,None,None,0,0]
                                                 bid = None
#                                                 logging.info("typeID = %s, SS = %s." % (typeID,solarSystemID))

                                             if bid != marketstat[7]:
                                                 bid = marketstat[7]
                                                 _shift = 0
                                                 if bid == 'True':
                                                     _shift = 4
                                                 ordersdata [_shift] = tdate
                                                 ordersdata [_shift+1] = tdate
                                             if bid  == 'True':
                                                 buyprices.append(long(float(marketstat[0])*100))
                                             else:
                                                 sellprices.append(long(float(marketstat[0])*100))
                                             if tdate > ordersdata [_shift] :
                                                 ordersdata [_shift] = tdate
                                             elif tdate < ordersdata [_shift+1]:
                                                 ordersdata [_shift+1] = tdate
                                             ordersdata [_shift+3] += long(float(marketstat[1]))
                                             ordersdata [_shift+2] += long(float(marketstat[5]))            
#                                             logging.info("Bid = %s, _shift = %d, tdate = %s, maxdate = %s, mindate = %s" % (str(bid),_shift,str(tdate),str(ordersdata[_shift]),str(ordersdata[_shift+1])))
                                except DeadlineExceededError:
                                  logging.info("Aborted at line %d. Processed %d records." % (marketlistIndex,_processed))
                                  return 
                            if typeID != None :
                                try:
                                    _processed += db.run_in_transaction(self.store_result,uploaded,long(typeID),long(regionID),long(solarSystemID),ordersdata,sellprices,buyprices)
                                    memcache.delete(cachedkey) 
                                except (DeadlineExceededError, datastore_errors.Timeout):
                                    logging.info("Aborted at line %d. Processed %d records." % (marketlistIndex,_processed))
                                    return 
                    try:
                        inboundmail.delete() 
                    except DeadlineExceededError:
                        logging.info("Aborted. Processed %d records." % (_processed))
                        return 
                    else:
                        logging.info("Finished. Processed %d records." % (_processed))
                except DeadlineExceededError:
                    logging.info("Aborted. Processed %d records." % (_processed))
                    return 
        except DeadlineExceededError:
            logging.info("Aborted.")
            return 
        return 

    def store_result(self,_uploaded,_typeID,_regionID,_solarSystemID,_ordersdata,_sellprices,_buyprices):
        statkey = "%06d%09d" % (_typeID,_solarSystemID)
        _date = _uploaded.date()
        historykey = _date.isoformat() + statkey
        marketstat = MarketStats.get_by_key_name(statkey)
        _put = True
        _sellpricesLen = len(_sellprices)
        _buypricesLen = len(_buyprices)
#        logging.info("marketstat = %s",(str(marketstat)))
        if marketstat == None:
#           logging.info("New entry in MarketStats: typeID = %d, solarSystemID = %d" % (_typeID,_solarSystemID))
           marketstat = MarketStats(typeID = _typeID, 
                                  solarSystemID = _solarSystemID,
                                  key_name = statkey)
           marketstat.regionID = _regionID
           markethistory = None
        else: 
#           logging.info("Updated entry in MarketStats: typeID = %d, solarSystemID = %d" % (_typeID,_solarSystemID))
           if (marketstat.updated.date() > _date)  or ((marketstat.ordersSell == _sellpricesLen) and 
                                                        (marketstat.volSellRemaining == _ordersdata[3]) and 
                                                        (marketstat.volSellEntered == _ordersdata[2]) and 
                                                        (marketstat.newestSellOrder == _ordersdata[0]) and
                                                        (marketstat.ordersBuy == _buypricesLen) and 
                                                        (marketstat.volBuyRemaining == _ordersdata[7]) and 
                                                        (marketstat.volBuyEntered == _ordersdata[6]) and 
                                                        (marketstat.newestBuyOrder == _ordersdata[4])
                                                        ):
#               logging.info("The same data. No need update!")
               _put = False
           else:
               markethistory = MarketHistory.get_by_key_name(historykey, parent = marketstat.key())
        if _put:
            marketstat.updated = _uploaded
            marketstat.ordersSell= _sellpricesLen
            if _sellpricesLen > 0:
                _sellprices.sort(cmp=numeric_compare)
                marketstat.minSellPrice = _sellprices[0]
                marketstat.maxSellPrice = _sellprices[-1]
                marketstat.averageSellPrice = sum(_sellprices) / _sellpricesLen
                if not _sellpricesLen % 2 :
                    marketstat.medianSellPrice = (_sellprices[(_sellpricesLen/2)-1] + _sellprices[_sellpricesLen/2]) / 2
                else:
                    marketstat.medianSellPrice = _sellprices[_sellpricesLen/2]
                marketstat.volSellEntered = _ordersdata[2]
                marketstat.volSellRemaining = _ordersdata[3]
                marketstat.newestSellOrder = _ordersdata[0]
                marketstat.oldestSellOrder = _ordersdata[1]
            marketstat.ordersBuy= _buypricesLen
            if _buypricesLen > 0:
                _buyprices.sort(cmp=numeric_compare)
                marketstat.minBuyPrice = _buyprices[0]
                marketstat.maxBuyPrice = _buyprices[-1]
                marketstat.averageBuyPrice = sum(_buyprices) / _buypricesLen
                if not _buypricesLen % 2 :
                    marketstat.medianBuyPrice = (_buyprices[(_buypricesLen/2)-1] + _buyprices[_buypricesLen/2]) / 2
                else:
                    marketstat.medianBuyPrice = _buyprices[_buypricesLen/2]
                marketstat.volBuyEntered = _ordersdata[6]
                marketstat.volBuyRemaining = _ordersdata[7]
                marketstat.newestBuyOrder = _ordersdata[4]
                marketstat.oldestBuyOrder = _ordersdata[5]
        
            if markethistory == None:
#               logging.info("New entry in MarketHistory: date = %s, typeID = %d, solarSystemID = %d" % (_date.isoformat(),_typeID,_solarSystemID))
               markethistory = MarketHistory(typeID = marketstat.typeID, 
                                            solarSystemID = marketstat.solarSystemID,
                                            date = _date, parent = marketstat,
                                            key_name = historykey)
               markethistory.regionID = marketstat.regionID
#            else:
#               logging.info("Updated entry in MarketHistory: date = %s, typeID = %d, solarSystemID = %d" % (_date.isoformat(),_typeID,_solarSystemID))
            markethistory.updated = _uploaded
            markethistory.ordersSell = marketstat.ordersSell
            markethistory.minSellPrice = marketstat.minSellPrice
            markethistory.maxSellPrice = marketstat.maxSellPrice
            markethistory.averageSellPrice = marketstat.averageSellPrice
            markethistory.medianSellPrice = marketstat.medianSellPrice
            markethistory.volSellRemaining = marketstat.volSellRemaining
            markethistory.volSellEntered = marketstat.volSellEntered
            markethistory.newestSellOrder = marketstat.newestSellOrder
            markethistory.oldestSellOrder = marketstat.oldestSellOrder
            markethistory.ordersBuy = marketstat.ordersBuy
            markethistory.minBuyPrice = marketstat.minBuyPrice
            markethistory.maxBuyPrice = marketstat.maxBuyPrice
            markethistory.averageBuyPrice = marketstat.averageBuyPrice
            markethistory.medianBuyPrice = marketstat.medianBuyPrice
            markethistory.volBuyRemaining = marketstat.volBuyRemaining
            markethistory.volBuyEntered = marketstat.volBuyEntered
            markethistory.newestBuyOrder = marketstat.newestBuyOrder
            markethistory.oldestBuyOrder = marketstat.oldestBuyOrder
        
            db.put([marketstat,markethistory])
            return(2)
        return(0)

application = webapp.WSGIApplication([('/.*', MainPage)], debug=True) 


def numeric_compare(x, y):
    if x > y:
        return 1
    elif x == y:
        return 0
    else: # x<y
        return -1

def main(): 
     run_wsgi_app(application) 

if __name__ == '__main__': 
     main() 